'use strict';
var m = Object.defineProperty;
var w = (o, e, t) =>
  e in o
    ? m(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t })
    : (o[e] = t);
var l = (o, e, t) => (w(o, typeof e != 'symbol' ? e + '' : e, t), t);
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const d = require('./cst.cjs'),
  b = require('./lexer.cjs');
function c(o, e) {
  for (let t = 0; t < o.length; ++t) if (o[t].type === e) return !0;
  return !1;
}
function f(o) {
  for (let e = 0; e < o.length; ++e)
    switch (o[e].type) {
      case 'space':
      case 'comment':
      case 'newline':
        break;
      default:
        return e;
    }
  return -1;
}
function k(o) {
  switch (o == null ? void 0 : o.type) {
    case 'alias':
    case 'scalar':
    case 'single-quoted-scalar':
    case 'double-quoted-scalar':
    case 'flow-collection':
      return !0;
    default:
      return !1;
  }
}
function u(o) {
  switch (o.type) {
    case 'document':
      return o.start;
    case 'block-map': {
      const e = o.items[o.items.length - 1];
      return e.sep ?? e.start;
    }
    case 'block-seq':
      return o.items[o.items.length - 1].start;
    default:
      return [];
  }
}
function h(o) {
  var t;
  if (o.length === 0) return [];
  let e = o.length;
  e: for (; --e >= 0; )
    switch (o[e].type) {
      case 'doc-start':
      case 'explicit-key-ind':
      case 'map-value-ind':
      case 'seq-item-ind':
      case 'newline':
        break e;
    }
  for (; ((t = o[++e]) == null ? void 0 : t.type) === 'space'; );
  return o.splice(e, o.length);
}
function y(o) {
  if (o.start.type === 'flow-seq-start')
    for (const e of o.items)
      e.sep &&
        !e.value &&
        !c(e.start, 'explicit-key-ind') &&
        !c(e.sep, 'map-value-ind') &&
        (e.key && (e.value = e.key),
        delete e.key,
        k(e.value)
          ? e.value.end
            ? Array.prototype.push.apply(e.value.end, e.sep)
            : (e.value.end = e.sep)
          : Array.prototype.push.apply(e.start, e.sep),
        delete e.sep);
}
class T {
  constructor(e) {
    l(this, 'onNewLine');
    l(this, 'atNewLine', !0);
    l(this, 'atScalar', !1);
    l(this, 'indent', 0);
    l(this, 'offset', 0);
    l(this, 'onKeyLine', !1);
    l(this, 'stack', []);
    l(this, 'source', '');
    l(this, 'type', '');
    l(this, 'lexer', new b.Lexer());
    this.onNewLine = e;
  }
  *parse(e, t = !1) {
    this.onNewLine && this.offset === 0 && this.onNewLine(0);
    for (const i of this.lexer.lex(e, t)) yield* this.next(i);
    t || (yield* this.end());
  }
  *next(e) {
    if (
      ((this.source = e),
      process.env.NODE_ENV === 'development' &&
        console.log('|', d.prettyToken(e)),
      this.atScalar)
    ) {
      (this.atScalar = !1), yield* this.step(), (this.offset += e.length);
      return;
    }
    const t = d.tokenType(e);
    if (t)
      if (t === 'scalar')
        (this.atNewLine = !1), (this.atScalar = !0), (this.type = 'scalar');
      else {
        switch (((this.type = t), yield* this.step(), t)) {
          case 'newline':
            (this.atNewLine = !0),
              (this.indent = 0),
              this.onNewLine && this.onNewLine(this.offset + e.length);
            break;
          case 'space':
            this.atNewLine && e[0] === ' ' && (this.indent += e.length);
            break;
          case 'explicit-key-ind':
          case 'map-value-ind':
          case 'seq-item-ind':
            this.atNewLine && (this.indent += e.length);
            break;
          case 'doc-mode':
          case 'flow-error-end':
            return;
          default:
            this.atNewLine = !1;
        }
        this.offset += e.length;
      }
    else {
      const i = `Not a YAML token: ${e}`;
      yield* this.pop({
        type: 'error',
        offset: this.offset,
        message: i,
        source: e,
      }),
        (this.offset += e.length);
    }
  }
  *end() {
    for (; this.stack.length > 0; ) yield* this.pop();
  }
  get sourceToken() {
    return {
      type: this.type,
      offset: this.offset,
      indent: this.indent,
      source: this.source,
    };
  }
  *step() {
    const e = this.peek(1);
    if (this.type === 'doc-end' && (!e || e.type !== 'doc-end')) {
      for (; this.stack.length > 0; ) yield* this.pop();
      this.stack.push({
        type: 'doc-end',
        offset: this.offset,
        source: this.source,
      });
      return;
    }
    if (!e) return yield* this.stream();
    switch (e.type) {
      case 'document':
        return yield* this.document(e);
      case 'alias':
      case 'scalar':
      case 'single-quoted-scalar':
      case 'double-quoted-scalar':
        return yield* this.scalar(e);
      case 'block-scalar':
        return yield* this.blockScalar(e);
      case 'block-map':
        return yield* this.blockMap(e);
      case 'block-seq':
        return yield* this.blockSequence(e);
      case 'flow-collection':
        return yield* this.flowCollection(e);
      case 'doc-end':
        return yield* this.documentEnd(e);
    }
    yield* this.pop();
  }
  peek(e) {
    return this.stack[this.stack.length - e];
  }
  *pop(e) {
    const t = e ?? this.stack.pop();
    if (t)
      if (this.stack.length === 0) yield t;
      else {
        const i = this.peek(1);
        switch (
          (t.type === 'block-scalar'
            ? (t.indent = 'indent' in i ? i.indent : 0)
            : t.type === 'flow-collection' &&
              i.type === 'document' &&
              (t.indent = 0),
          t.type === 'flow-collection' && y(t),
          i.type)
        ) {
          case 'document':
            i.value = t;
            break;
          case 'block-scalar':
            i.props.push(t);
            break;
          case 'block-map': {
            const s = i.items[i.items.length - 1];
            if (s.value) {
              i.items.push({ start: [], key: t, sep: [] }),
                (this.onKeyLine = !0);
              return;
            } else if (s.sep) s.value = t;
            else {
              Object.assign(s, { key: t, sep: [] }),
                (this.onKeyLine = !c(s.start, 'explicit-key-ind'));
              return;
            }
            break;
          }
          case 'block-seq': {
            const s = i.items[i.items.length - 1];
            s.value ? i.items.push({ start: [], value: t }) : (s.value = t);
            break;
          }
          case 'flow-collection': {
            const s = i.items[i.items.length - 1];
            !s || s.value
              ? i.items.push({ start: [], key: t, sep: [] })
              : s.sep
                ? (s.value = t)
                : Object.assign(s, { key: t, sep: [] });
            return;
          }
          default:
            yield* this.pop(), yield* this.pop(t);
        }
        if (
          (i.type === 'document' ||
            i.type === 'block-map' ||
            i.type === 'block-seq') &&
          (t.type === 'block-map' || t.type === 'block-seq')
        ) {
          const s = t.items[t.items.length - 1];
          s &&
            !s.sep &&
            !s.value &&
            s.start.length > 0 &&
            f(s.start) === -1 &&
            (t.indent === 0 ||
              s.start.every(
                n => n.type !== 'comment' || n.indent < t.indent,
              )) &&
            (i.type === 'document'
              ? (i.end = s.start)
              : i.items.push({ start: s.start }),
            t.items.splice(-1, 1));
        }
      }
    else {
      const i = 'Tried to pop an empty stack';
      yield { type: 'error', offset: this.offset, source: '', message: i };
    }
  }
  *stream() {
    switch (this.type) {
      case 'directive-line':
        yield { type: 'directive', offset: this.offset, source: this.source };
        return;
      case 'byte-order-mark':
      case 'space':
      case 'comment':
      case 'newline':
        yield this.sourceToken;
        return;
      case 'doc-mode':
      case 'doc-start': {
        const e = { type: 'document', offset: this.offset, start: [] };
        this.type === 'doc-start' && e.start.push(this.sourceToken),
          this.stack.push(e);
        return;
      }
    }
    yield {
      type: 'error',
      offset: this.offset,
      message: `Unexpected ${this.type} token in YAML stream`,
      source: this.source,
    };
  }
  *document(e) {
    if (e.value) return yield* this.lineEnd(e);
    switch (this.type) {
      case 'doc-start': {
        f(e.start) !== -1
          ? (yield* this.pop(), yield* this.step())
          : e.start.push(this.sourceToken);
        return;
      }
      case 'anchor':
      case 'tag':
      case 'space':
      case 'comment':
      case 'newline':
        e.start.push(this.sourceToken);
        return;
    }
    const t = this.startBlockValue(e);
    t
      ? this.stack.push(t)
      : yield {
          type: 'error',
          offset: this.offset,
          message: `Unexpected ${this.type} token in YAML document`,
          source: this.source,
        };
  }
  *scalar(e) {
    if (this.type === 'map-value-ind') {
      const t = u(this.peek(2)),
        i = h(t);
      let s;
      e.end
        ? ((s = e.end), s.push(this.sourceToken), delete e.end)
        : (s = [this.sourceToken]);
      const n = {
        type: 'block-map',
        offset: e.offset,
        indent: e.indent,
        items: [{ start: i, key: e, sep: s }],
      };
      (this.onKeyLine = !0), (this.stack[this.stack.length - 1] = n);
    } else yield* this.lineEnd(e);
  }
  *blockScalar(e) {
    switch (this.type) {
      case 'space':
      case 'comment':
      case 'newline':
        e.props.push(this.sourceToken);
        return;
      case 'scalar':
        if (
          ((e.source = this.source),
          (this.atNewLine = !0),
          (this.indent = 0),
          this.onNewLine)
        ) {
          let t =
            this.source.indexOf(`
`) + 1;
          for (; t !== 0; )
            this.onNewLine(this.offset + t),
              (t =
                this.source.indexOf(
                  `
`,
                  t,
                ) + 1);
        }
        yield* this.pop();
        break;
      default:
        yield* this.pop(), yield* this.step();
    }
  }
  *blockMap(e) {
    var i;
    const t = e.items[e.items.length - 1];
    switch (this.type) {
      case 'newline':
        if (((this.onKeyLine = !1), t.value)) {
          const s = 'end' in t.value ? t.value.end : void 0,
            n = Array.isArray(s) ? s[s.length - 1] : void 0;
          (n == null ? void 0 : n.type) === 'comment'
            ? s == null || s.push(this.sourceToken)
            : e.items.push({ start: [this.sourceToken] });
        } else
          t.sep ? t.sep.push(this.sourceToken) : t.start.push(this.sourceToken);
        return;
      case 'space':
      case 'comment':
        if (t.value) e.items.push({ start: [this.sourceToken] });
        else if (t.sep) t.sep.push(this.sourceToken);
        else {
          if (this.atIndentedComment(t.start, e.indent)) {
            const s = e.items[e.items.length - 2],
              n = (i = s == null ? void 0 : s.value) == null ? void 0 : i.end;
            if (Array.isArray(n)) {
              Array.prototype.push.apply(n, t.start),
                n.push(this.sourceToken),
                e.items.pop();
              return;
            }
          }
          t.start.push(this.sourceToken);
        }
        return;
    }
    if (this.indent >= e.indent) {
      const s = !this.onKeyLine && this.indent === e.indent && t.sep;
      let n = [];
      if (s && t.sep && !t.value) {
        const a = [];
        for (let r = 0; r < t.sep.length; ++r) {
          const p = t.sep[r];
          switch (p.type) {
            case 'newline':
              a.push(r);
              break;
            case 'space':
              break;
            case 'comment':
              p.indent > e.indent && (a.length = 0);
              break;
            default:
              a.length = 0;
          }
        }
        a.length >= 2 && (n = t.sep.splice(a[1]));
      }
      switch (this.type) {
        case 'anchor':
        case 'tag':
          s || t.value
            ? (n.push(this.sourceToken),
              e.items.push({ start: n }),
              (this.onKeyLine = !0))
            : t.sep
              ? t.sep.push(this.sourceToken)
              : t.start.push(this.sourceToken);
          return;
        case 'explicit-key-ind':
          !t.sep && !c(t.start, 'explicit-key-ind')
            ? t.start.push(this.sourceToken)
            : s || t.value
              ? (n.push(this.sourceToken), e.items.push({ start: n }))
              : this.stack.push({
                  type: 'block-map',
                  offset: this.offset,
                  indent: this.indent,
                  items: [{ start: [this.sourceToken] }],
                }),
            (this.onKeyLine = !0);
          return;
        case 'map-value-ind':
          if (c(t.start, 'explicit-key-ind'))
            if (t.sep)
              if (t.value)
                e.items.push({ start: [], key: null, sep: [this.sourceToken] });
              else if (c(t.sep, 'map-value-ind'))
                this.stack.push({
                  type: 'block-map',
                  offset: this.offset,
                  indent: this.indent,
                  items: [{ start: n, key: null, sep: [this.sourceToken] }],
                });
              else if (k(t.key) && !c(t.sep, 'newline')) {
                const a = h(t.start),
                  r = t.key,
                  p = t.sep;
                p.push(this.sourceToken),
                  delete t.key,
                  delete t.sep,
                  this.stack.push({
                    type: 'block-map',
                    offset: this.offset,
                    indent: this.indent,
                    items: [{ start: a, key: r, sep: p }],
                  });
              } else
                n.length > 0
                  ? (t.sep = t.sep.concat(n, this.sourceToken))
                  : t.sep.push(this.sourceToken);
            else if (c(t.start, 'newline'))
              Object.assign(t, { key: null, sep: [this.sourceToken] });
            else {
              const a = h(t.start);
              this.stack.push({
                type: 'block-map',
                offset: this.offset,
                indent: this.indent,
                items: [{ start: a, key: null, sep: [this.sourceToken] }],
              });
            }
          else
            t.sep
              ? t.value || s
                ? e.items.push({ start: n, key: null, sep: [this.sourceToken] })
                : c(t.sep, 'map-value-ind')
                  ? this.stack.push({
                      type: 'block-map',
                      offset: this.offset,
                      indent: this.indent,
                      items: [
                        { start: [], key: null, sep: [this.sourceToken] },
                      ],
                    })
                  : t.sep.push(this.sourceToken)
              : Object.assign(t, { key: null, sep: [this.sourceToken] });
          this.onKeyLine = !0;
          return;
        case 'alias':
        case 'scalar':
        case 'single-quoted-scalar':
        case 'double-quoted-scalar': {
          const a = this.flowScalar(this.type);
          s || t.value
            ? (e.items.push({ start: n, key: a, sep: [] }),
              (this.onKeyLine = !0))
            : t.sep
              ? this.stack.push(a)
              : (Object.assign(t, { key: a, sep: [] }), (this.onKeyLine = !0));
          return;
        }
        default: {
          const a = this.startBlockValue(e);
          if (a) {
            s &&
              a.type !== 'block-seq' &&
              c(t.start, 'explicit-key-ind') &&
              e.items.push({ start: n }),
              this.stack.push(a);
            return;
          }
        }
      }
    }
    yield* this.pop(), yield* this.step();
  }
  *blockSequence(e) {
    var i;
    const t = e.items[e.items.length - 1];
    switch (this.type) {
      case 'newline':
        if (t.value) {
          const s = 'end' in t.value ? t.value.end : void 0,
            n = Array.isArray(s) ? s[s.length - 1] : void 0;
          (n == null ? void 0 : n.type) === 'comment'
            ? s == null || s.push(this.sourceToken)
            : e.items.push({ start: [this.sourceToken] });
        } else t.start.push(this.sourceToken);
        return;
      case 'space':
      case 'comment':
        if (t.value) e.items.push({ start: [this.sourceToken] });
        else {
          if (this.atIndentedComment(t.start, e.indent)) {
            const s = e.items[e.items.length - 2],
              n = (i = s == null ? void 0 : s.value) == null ? void 0 : i.end;
            if (Array.isArray(n)) {
              Array.prototype.push.apply(n, t.start),
                n.push(this.sourceToken),
                e.items.pop();
              return;
            }
          }
          t.start.push(this.sourceToken);
        }
        return;
      case 'anchor':
      case 'tag':
        if (t.value || this.indent <= e.indent) break;
        t.start.push(this.sourceToken);
        return;
      case 'seq-item-ind':
        if (this.indent !== e.indent) break;
        t.value || c(t.start, 'seq-item-ind')
          ? e.items.push({ start: [this.sourceToken] })
          : t.start.push(this.sourceToken);
        return;
    }
    if (this.indent > e.indent) {
      const s = this.startBlockValue(e);
      if (s) {
        this.stack.push(s);
        return;
      }
    }
    yield* this.pop(), yield* this.step();
  }
  *flowCollection(e) {
    const t = e.items[e.items.length - 1];
    if (this.type === 'flow-error-end') {
      let i;
      do yield* this.pop(), (i = this.peek(1));
      while (i && i.type === 'flow-collection');
    } else if (e.end.length === 0) {
      switch (this.type) {
        case 'comma':
        case 'explicit-key-ind':
          !t || t.sep
            ? e.items.push({ start: [this.sourceToken] })
            : t.start.push(this.sourceToken);
          return;
        case 'map-value-ind':
          !t || t.value
            ? e.items.push({ start: [], key: null, sep: [this.sourceToken] })
            : t.sep
              ? t.sep.push(this.sourceToken)
              : Object.assign(t, { key: null, sep: [this.sourceToken] });
          return;
        case 'space':
        case 'comment':
        case 'newline':
        case 'anchor':
        case 'tag':
          !t || t.value
            ? e.items.push({ start: [this.sourceToken] })
            : t.sep
              ? t.sep.push(this.sourceToken)
              : t.start.push(this.sourceToken);
          return;
        case 'alias':
        case 'scalar':
        case 'single-quoted-scalar':
        case 'double-quoted-scalar': {
          const s = this.flowScalar(this.type);
          !t || t.value
            ? e.items.push({ start: [], key: s, sep: [] })
            : t.sep
              ? this.stack.push(s)
              : Object.assign(t, { key: s, sep: [] });
          return;
        }
        case 'flow-map-end':
        case 'flow-seq-end':
          e.end.push(this.sourceToken);
          return;
      }
      const i = this.startBlockValue(e);
      i ? this.stack.push(i) : (yield* this.pop(), yield* this.step());
    } else {
      const i = this.peek(2);
      if (
        i.type === 'block-map' &&
        ((this.type === 'map-value-ind' && i.indent === e.indent) ||
          (this.type === 'newline' && !i.items[i.items.length - 1].sep))
      )
        yield* this.pop(), yield* this.step();
      else if (this.type === 'map-value-ind' && i.type !== 'flow-collection') {
        const s = u(i),
          n = h(s);
        y(e);
        const a = e.end.splice(1, e.end.length);
        a.push(this.sourceToken);
        const r = {
          type: 'block-map',
          offset: e.offset,
          indent: e.indent,
          items: [{ start: n, key: e, sep: a }],
        };
        (this.onKeyLine = !0), (this.stack[this.stack.length - 1] = r);
      } else yield* this.lineEnd(e);
    }
  }
  flowScalar(e) {
    if (this.onNewLine) {
      let t =
        this.source.indexOf(`
`) + 1;
      for (; t !== 0; )
        this.onNewLine(this.offset + t),
          (t =
            this.source.indexOf(
              `
`,
              t,
            ) + 1);
    }
    return {
      type: e,
      offset: this.offset,
      indent: this.indent,
      source: this.source,
    };
  }
  startBlockValue(e) {
    switch (this.type) {
      case 'alias':
      case 'scalar':
      case 'single-quoted-scalar':
      case 'double-quoted-scalar':
        return this.flowScalar(this.type);
      case 'block-scalar-header':
        return {
          type: 'block-scalar',
          offset: this.offset,
          indent: this.indent,
          props: [this.sourceToken],
          source: '',
        };
      case 'flow-map-start':
      case 'flow-seq-start':
        return {
          type: 'flow-collection',
          offset: this.offset,
          indent: this.indent,
          start: this.sourceToken,
          items: [],
          end: [],
        };
      case 'seq-item-ind':
        return {
          type: 'block-seq',
          offset: this.offset,
          indent: this.indent,
          items: [{ start: [this.sourceToken] }],
        };
      case 'explicit-key-ind': {
        this.onKeyLine = !0;
        const t = u(e),
          i = h(t);
        return (
          i.push(this.sourceToken),
          {
            type: 'block-map',
            offset: this.offset,
            indent: this.indent,
            items: [{ start: i }],
          }
        );
      }
      case 'map-value-ind': {
        this.onKeyLine = !0;
        const t = u(e),
          i = h(t);
        return {
          type: 'block-map',
          offset: this.offset,
          indent: this.indent,
          items: [{ start: i, key: null, sep: [this.sourceToken] }],
        };
      }
    }
    return null;
  }
  atIndentedComment(e, t) {
    return this.type !== 'comment' || this.indent <= t
      ? !1
      : e.every(i => i.type === 'newline' || i.type === 'space');
  }
  *documentEnd(e) {
    this.type !== 'doc-mode' &&
      (e.end ? e.end.push(this.sourceToken) : (e.end = [this.sourceToken]),
      this.type === 'newline' && (yield* this.pop()));
  }
  *lineEnd(e) {
    switch (this.type) {
      case 'comma':
      case 'doc-start':
      case 'doc-end':
      case 'flow-seq-end':
      case 'flow-map-end':
      case 'map-value-ind':
        yield* this.pop(), yield* this.step();
        break;
      case 'newline':
        this.onKeyLine = !1;
      case 'space':
      case 'comment':
      default:
        e.end ? e.end.push(this.sourceToken) : (e.end = [this.sourceToken]),
          this.type === 'newline' && (yield* this.pop());
    }
  }
}
exports.Parser = T;
